local skynet = require "skynet"
local websocket = require"websocket"
local json = require "cjson"
local dump_T = require "dump_t"

local pb = require "protobuf"
pb.register_file "./pbc/gctols.pb" 

local function send_game_msg(fd, msg_id, msg_name, data)
	local bytes = assert(pb.encode(msg_name, data))
	local ReqXieYi = {
		msgid = msg_id,
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	websocket:send_binary(fd,respData)
end

local function send_msg(fd,msg)
	websocket:send_binary(fd,msg)
end

local M = {}
M.__index = M

function M:myprepare( data )
	local isok = type(data)=="table"
	if isok then
		if data.nready == 1 then
			self.prepare = true
		else 
			self.prepare = false
		end
		-- 准备完成，发送resp
		local respReadyData = {
			askid = data.askid,
			roomid = data.roomid
		}
		local bytes = assert(pb.encode("GCToLS.RespReady", respReadyData))
		local ReqXieYi = {
			msgid = "eMsg_ReadyAck",
			data = bytes,
		}
		local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
		send_msg(self.fd,respData)
	end
	return isok
end

--取消准备
function M:cancelprepare()
	self.prepare = false
end

local function send_prepare_msg(fd,respPlayerReadyData)
	local bytes = assert(pb.encode("GCToLS.RespPlayerReady", respPlayerReadyData))
	local ReqXieYi = {
		msgid = "eMsg_PlayerPreare",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	websocket:send_binary(fd,respData)
end

function M:otherPrepare( pos,data )
	-- 有玩家准备状态变化，通知
	local respPlayerReadyData = {
		nseat = pos,
		uid = tostring(data.uid),
		nready = data.nready;
	}
	send_prepare_msg(self.fd,respPlayerReadyData)
end

local function send_playerdata_msg(fd,respPlayerEnterData)
	local bytes = assert(pb.encode("GCToLS.RespPlayerEnter", respPlayerEnterData))
	local ReqXieYi = {
		msgid = "eMsg_PlayerEnter",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	websocket:send_binary(fd,respData)
end


function M:enter(rid,others, askid)
	-- 成功加入房间
	local respJoinRoomData = {
		askid = askid,
		nflag = 0,
		nroomid = rid,
	}
	local bytes = assert(pb.encode("GCToLS.RespJoinRoom", respJoinRoomData))
	local ReqXieYi = {
		msgid = "eMsg_JoinRoomAck",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	
	send_msg(self.fd,respData)
	
	-- 发送自己的消息
	local respPlayerEnterData = {
		nseat = self.pos,
		uid = tostring(self.uid),
		nickname = self.nickname,
		headurl = self.headurl,
		sex = self.sex,
	}
	send_playerdata_msg(self.fd,respPlayerEnterData)
	-- 发送已经在的玩家
	for i, player in pairs(others) do
		local respPlayerEnterData = {
			nseat = player.pos,
			uid = tostring(player.uid),
			nickname = player.nickname,
			headurl = player.headurl,
			sex = player.sex,
		}
		send_playerdata_msg(self.fd, respPlayerEnterData)
		-- 玩家已经准备
		if player.prepare then
			local respPlayerReadyData = {
				nseat = player.pos,
				uid = tostring(player.uid),
				nready = player.prepare and 1 or 0;
			}
			send_prepare_msg(self.fd,respPlayerReadyData)
		end
		
	end
end

function M:otherEnter(other)
	--别的玩家进入,发送玩家进入协议
	local respPlayerEnterData = {
		nseat = other.pos,
		uid = tostring(other.uid),
		nickname = other.nickname,
		headurl = other.headurl,
		sex = other.sex,
	}
	send_playerdata_msg(self.fd, respPlayerEnterData)
end

function M:exit( )
	
end

function M:otherExit( pos, userinfo)
	--别的玩家退出,发送玩家退出协议
	local respPlayerLeaveData = {
		nseat = pos,
		uid = tostring(userinfo.uid),
		nickname = userinfo.nickname,
	}
	local bytes = assert(pb.encode("GCToLS.RespPlayerLeave", respPlayerLeaveData))
	local ReqXieYi = {
		msgid = "eMsg_PlayerLeave",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	send_msg(self.fd,respData)
end

function M:getInfo( )
	return {
		pos = self.pos,
		nickname = self.nickname,
		coin = self.coin,
		sex = self.sex,
		prepare = self.prepare,
		uid = self.uid,
		headurl = self.headurl,
	}
end

function M:error(cmd_id,f)
	
end

-----------------------------------------
function M:sendAllPlayerReady()
	--别的玩家退出,发送玩家退出协议
	local respAllPlayerReadyData = {
		nseat = pos,
		nflag = 0,
	}
	local bytes = assert(pb.encode("GCToLS.RespAllPlayerReady", respAllPlayerReadyData))
	local ReqXieYi = {
		msgid = "eMsg_AllPlayerReady",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	send_msg(self.fd,respData)
end

function M:sendPlanePostion(pos, position)
	-- 发送别的玩家的位置
	local respPlanePosData = {
		nseat = pos,
		plane = {
			planeid = pos,
			ntype = 1,
			pos = position,
		}
	}
	local bytes = assert(pb.encode("GCToLS.RespPlanePos", respPlanePosData))
	local ReqXieYi = {
		msgid = "eMsg_PlayerPlane",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	send_msg(self.fd,respData)
end

function M:sendGameData(enemyplane, bullet, fitplane)
	local respGameData = {
		bullet = {},
		bulletaction = {},
		bulletactstate = {},
		enemyairplane = {},
		enemyaction = {},
		enemyactstate = {},
		fitplane = {},
	}
	for i , e in pairs (enemyplane) do
		local info = e:getInfo();
		local eT = {
			id = info.idx;				
			nangle = info.angle; 			
			pos =  {nXpos = info.posX,  nYpos = info.posY};				
			nspeed = info.speed * 50;			
			ntype = 1;			
			nblood = info.blood;			
			nbehavior = info.behavior;		
		}
		local eaction = {
			id = info.idx,
			actiontype = {}
		}
		for i , action in pairs(e:getActionArray()) do
			local tdata = {
				actiontype = action.actionenum,		
				nangle = action.angle,
				startpos = { },
				endpos = { },
				time = action.ttime,
				nquan = action.nquan,
			}
			if action.startpos then
				tdata.startpos = { nXpos = action.startpos.x ,nYpos = action.startpos.y }
			end
			if action.endpos then
				tdata.endpos = { nXpos = action.endpos.x ,nYpos = action.endpos.y }
			end
			table.insert(eaction.actiontype, tdata); 
		end
		local state = e:getActionStats();
		local actionState = {
			id = info.idx,
			actionstep = state.actionstep,
			actionsteptime = state.steptime,
		}
		table.insert(respGameData.enemyaction, eaction); 
		table.insert(respGameData.enemyairplane, eT); 
		table.insert(respGameData.enemyactstate, actionState); 
	end
	
	for i , b in pairs (bullet) do
		local info = b:getInfo();
		local bT = {
			id = info.idx;				
			nangle = info.angle; 			
			pos =  {nXpos = info.posX,  nYpos = info.posY};				
			nspeed = info.speed * 50;			
			ntype = info.ntype;				
		}
		table.insert(respGameData.bullet, bT); 
		local bulletT = {
			id = info.idx,					
			actiontype = {}				
		}
		for i , action in pairs(b:getActionArray()) do
			local tdata = {
				actiontype = action.actiontype,		
				nangle = action.nangle,
				startpos = { },
				endpos = { },
			}
			if action.startpos then
				tdata.startpos = { nXpos = action.startpos.nXpos ,nYpos = action.startpos.nYpos }
			end
			if action.endpos then
				tdata.endpos = { nXpos = action.endpos.nXpos ,nYpos = action.endpos.nYpos }
			end
			table.insert(bulletT.actiontype, tdata); 
		end
		local state = b:getActionStats();
		local actionState = {
			id = info.idx,
			actionstep = state.actionstep,
			actionsteptime = state.steptime,
		}
		table.insert(respGameData.bulletaction, bulletT); 
		table.insert(respGameData.bulletactstate, actionState); 
	end
	for i, fitplane in pairs(fitplane) do
		local info = fitplane:getInfo();
		local fT = {
			id = info.idx;				
			nangle = info.angle; 			
			pos =  {nXpos = info.posX,  nYpos = info.posY};				
			nspeed = info.speed * 50;			
			ntype = 1;			
			nblood = info.blood;					
		}
		table.insert(respGameData.fitplane, fT); 
	end
	
	local bytes = assert(pb.encode("GCToLS.RespGameData", respGameData))
	local ReqXieYi = {
		msgid = "eMsg_GameData",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	send_msg(self.fd,respData)
end 

--发送敌机事件
function M:sendEnemyEvent(eventtype, enemyplane, enemymovearray)
	local respData = {
		neventype = -1,
		enemyairplane = {},
		enemyaction = {},
	}
	
	if eventtype == 0 then
		respData.neventype = 0
		for i, e in pairs(enemyplane) do
			local info = e:getInfo();
			local ep = {
				id = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = 1;			
				nblood = info.blood;			
				nbehavior = info.behavior;		
			}
			table.insert(respData.enemyairplane, ep); 
		end
		
	elseif eventtype == 1 then
		respData.neventype = 1
		for i, enemy in pairs(enemymovearray) do
			local e = {
				id = enemy.idx,
				actiontype = {}
			}
			for i , action in pairs(enemy.moveaction) do
				local tdata = {
					actiontype = action.actionenum,		
					nangle = action.angle,
					startpos = { },
					endpos = { },
					time = action.ttime,
					nquan = action.nquan,
				}
				if action.startpos then
					tdata.startpos = { nXpos = action.startpos.x ,nYpos = action.startpos.y }
				end
				if action.endpos then
					tdata.endpos = { nXpos = action.endpos.x ,nYpos = action.endpos.y }
				end
				table.insert(e.actiontype, tdata); 
			end
			table.insert(respData.enemyaction, e); 
		end
	elseif eventtype == 2 then
		respData.neventype = 2
		for i, e in pairs(enemyplane) do
			local info = e:getInfo();
			local ep = {
				id = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = 1;			
				nblood = info.blood;			
				nbehavior = info.behavior;
				nReduceBlood = e.disblood,
			}
			table.insert(respData.enemyairplane, ep); 
		end
	elseif eventtype == 3 then
		respData.neventype = 3
		for i, e in pairs(enemyplane) do
			local info = e:getInfo();
			local e = {
				id = info.idx;				
			}
			table.insert(respData.enemyairplane, e); 
		end
		
	end
	
	send_game_msg(self.fd, "eMsg_EnemyPlaneEvent", "GCToLS.RespEnemyPlaneEvent",respData)
end

--发送子弹事件
function M:sendBulletEvent(eventtype, bullet, bulletmove)
	local respData = {
		neventype = -1,
		bullet = {},
		bulletaction = {},
	}
	if eventtype == 0 then
		respData.neventype = 0
		for i, b in pairs(bullet) do
			local info = b:getInfo();
			local bulletT = {
				id = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;		
			}
			table.insert(respData.bullet, bulletT); 
		end
	elseif eventtype == 1 then
		respData.neventype = 1
		for i, b in pairs(bulletmove) do
			local bulletT = {
				id = b.idx,					
				actiontype = {}				
			}
			for i , action in pairs(b.actiontype) do
				local tdata = {
					actiontype = action.actiontype,		
					nangle = action.nangle,
					startpos = { },
					endpos = { },
				}
				if action.startpos then
					tdata.startpos = { nXpos = action.startpos.nXpos ,nYpos = action.startpos.nYpos }
				end
				if action.endpos then
					tdata.endpos = { nXpos = action.endpos.nXpos ,nYpos = action.endpos.nYpos }
				end
				table.insert(bulletT.actiontype, tdata); 
			end
			table.insert(respData.bulletaction, bulletT); 
		end
	elseif eventtype == 3 then
		respData.neventype = 3
		for i, b in pairs(bullet) do
			local info = b:getInfo();
			local bulletT = {
				id = info.idx;				
			}
			table.insert(respData.bullet, bulletT); 
		end
	end
	
	send_game_msg(self.fd, "eMsg_BulletEvent", "GCToLS.RespBulletEvent",respData)
end

-- 发送玩家飞机事件
function M:sendPlaneEvent(eventtype, plane, ntime)
	local respData = {
		neventype = 0;
		plane = {},
	}
	if eventtype == 0 then
		respData.neventype = 0
		for i, p in pairs(plane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;			
			}
			table.insert(respData.plane, planeT); 
		end
	elseif eventtype == 1 then
		respData.neventype = 1
	elseif eventtype == 2 then
		-- 合体
		respData.neventype = 2
		for i, p in pairs(plane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;	
				nState = info.nState;
			}
			table.insert(respData.plane, planeT); 
		end
	elseif eventtype == 3 then
		-- 解体
		respData.neventype = 3
		for i, p in pairs(plane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;	
				nState = info.nState;
			}
			table.insert(respData.plane, planeT); 
		end
	elseif eventtype == 4 then
		-- 开始合体
		respData.neventype = 4
		respData.ntime = ntime
		for i, p in pairs(plane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;	
				nState = info.nState;
			}
			table.insert(respData.plane, planeT); 
		end
	elseif eventtype == 5 then
		respData.neventype = 5
		for i, p in pairs(plane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;	
				nState = info.nState;
			}
			table.insert(respData.plane, planeT); 
		end
	end
	send_game_msg(self.fd, "eMsg_PlayerPlaneEvent", "GCToLS.RespPlayerPlaneEvnet",respData)
end

-- 发送合体飞机事件
function M:sendFitPlaneEvent(eventtype, fitplane)
	local respData = {
		neventype = 0;
		fitplane = {},
	}
	if eventtype == 0 then
		respData.neventype = 0
		for i, p in pairs(fitplane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;			
			}
			table.insert(respData.fitplane, planeT); 
		end
	elseif eventtype == 1 then
		respData.neventype = 1
		for i, p in pairs(fitplane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;			
			}
			table.insert(respData.fitplane, planeT); 
		end
	elseif eventtype == 2 then
		respData.neventype = 2
		for i, p in pairs(fitplane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;			
			}
			table.insert(respData.fitplane, planeT); 
		end
	elseif eventtype == 3 then
		-- 解体
		respData.neventype = 3
		for i, p in pairs(fitplane) do
			local info = p:getInfo();
			local planeT = {
				planeid = info.idx;				
				nangle = info.angle; 			
				pos =  {nXpos = info.posX,  nYpos = info.posY};				
				nspeed = info.speed * 50;			
				ntype = info.ntype;			
				nblood = info.blood;			
				nbehavior = info.behavior;	
				nReduceBlood = p.disblood;			
			}
			table.insert(respData.fitplane, planeT); 
		end
	end
	send_game_msg(self.fd, "eMsg_FitPlaneEvent", "GCToLS.RespFitPlaneEvent",respData)
end

--玩家加载完成,发送开始游戏
function M:sendGameStart()
	-- 发送别的玩家的位置
	local respGameStartData = {
		nseat = pos,
		nflag = 0,
	}
	local bytes = assert(pb.encode("GCToLS.RespGameStart", respGameStartData))
	local ReqXieYi = {
		msgid = "eMsg_GameStart",
		data = bytes,
	}
	local respData = assert(pb.encode("GCToLS.ReqXieYi", ReqXieYi))
	send_msg(self.fd,respData)
end

--玩家初始飞机位置发送
function M:sendInitPlane(playerPlaneArray)
	for i = 1, #playerPlaneArray do
		local info = playerPlaneArray[i]:getInfo()
		local respData = {
			nseat = i,
			plane = {
				planeid = info.idx,
				ntype = 0,
				pos = { nXpos = info.posX, nYpos = info.posY},
				nblood = info.blood,
				nbehavior = 1,
			},
		}
		send_game_msg(self.fd, "eMsg_PLayerPlaneData", "GCToLS.RespPlayerPlaneData",respData)
	end
end

--第几步发送
function M:sendGameStep(stepcount)
	local respData = {
		nstep = stepcount;
	}
	send_game_msg(self.fd, "eMsg_GameStepStart", "GCToLS.RespGameStepStart",respData)
end
--------------------------------------------------------

function M:gameOver()
	local respData = {
		nflag = 1;
	}
	send_game_msg(self.fd, "eMsg_GameOver", "GCToLS.RespGameOver",respData)
end
-----------------------------------------

function M:relink(info, con)
	self.fd = con.fd
	print("player relink fd =" .. self.fd)
end

function M.new( pos,info,con )
	local instance = setmetatable({
		pos = pos,
		prepare = false,
		coin = info.coin,
		nickname = info.nickname,
		sex = info.sex,
		uid = con.uid,
		fd = con.fd,
		headurl =info.headurl,
	},M)
	return instance
end

return M
